package com.bz.websocket.utils;

import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * Created on 2019/7/3
 *
 * 断言工具
 *
 * @author zhongyongbin
 */
public final class AssertUtil {

    private AssertUtil() {
    }

    /**
     * 必须相等
     *
     * @param obj1     比较对象 1
     * @param obj2     比较对象 2
     * @param supplier 异常提供函数
     * @param <X>      异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireEqual(Object obj1, Object obj2, Supplier<X> supplier) throws X {
        if (!Objects.equals(obj1, obj2)) {
            throw supplier.get();
        }
    }

    /**
     * 必须不相等
     *
     * @param obj1     比较对象 1
     * @param obj2     比较对象 2
     * @param supplier 异常提供函数
     * @param <X>      异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNotEqual(Object obj1, Object obj2, Supplier<X> supplier) throws X {
        if (Objects.equals(obj1, obj2)) {
            throw supplier.get();
        }
    }

    /**
     * 必须为真
     *
     * @param bool     布尔值
     * @param supplier 异常提供函数
     * @param <X>      异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireTrue(boolean bool, Supplier<X> supplier) throws X {
        if (!bool) {
            throw supplier.get();
        }
    }

    /**
     * 必须为假
     *
     * @param bool     布尔值
     * @param supplier 异常提供函数
     * @param <X>      异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireFalse(boolean bool, Supplier<X> supplier) throws X {
        if (bool) {
            throw supplier.get();
        }
    }

    /**
     * 必须不为空
     *
     * @param object   判断对象
     * @param supplier 异常提供函数
     * @param <X>      异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNonNull(Object object, Supplier<X> supplier) throws X {
        if (Objects.isNull(object)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须在指定范围
     *
     * @param number            数值
     * @param leftCloseInterval 左边界，为闭区间
     * @param rightOpenInterval 右边界，为开区间
     * @param supplier          异常提供函数
     * @param <X>               异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberInRange(int number, int leftCloseInterval, int rightOpenInterval, Supplier<X> supplier) throws X {
        if (!(number >= leftCloseInterval && number < rightOpenInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须大于指定范围
     *
     * @param number           数值
     * @param leftOpenInterval 左边界，为开区间
     * @param supplier         异常提供函数
     * @param <X>              异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberGtRange(int number, int leftOpenInterval, Supplier<X> supplier) throws X {
        if (!(number > leftOpenInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须大于等于指定范围
     *
     * @param number            数值
     * @param leftCloseInterval 左边界，为闭区间
     * @param supplier          异常提供函数
     * @param <X>               异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberGteRange(int number, int leftCloseInterval, Supplier<X> supplier) throws X {
        if (!(number >= leftCloseInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须小于指定范围
     *
     * @param number            数值
     * @param rightOpenInterval 右边界，为开区间
     * @param supplier          异常提供函数
     * @param <X>               异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberLtRange(int number, int rightOpenInterval, Supplier<X> supplier) throws X {
        if (!(number < rightOpenInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须小于等于指定范围
     *
     * @param number             数值
     * @param rightCloseInterval 右边界，为闭区间
     * @param supplier           异常提供函数
     * @param <X>                异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberLteRange(int number, int rightCloseInterval, Supplier<X> supplier) throws X {
        if (!(number < rightCloseInterval)) {
            throw supplier.get();
        }
    }


    /**
     * 数值必须在指定范围
     *
     * @param number            数值
     * @param leftCloseInterval 左边界，为闭区间
     * @param rightOpenInterval 右边界，为开区间
     * @param supplier          异常提供函数
     * @param <X>               异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberInRange(long number, long leftCloseInterval, long rightOpenInterval, Supplier<X> supplier) throws X {
        if (!(number >= leftCloseInterval && number < rightOpenInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须大于指定范围
     *
     * @param number           数值
     * @param leftOpenInterval 左边界，为开区间
     * @param supplier         异常提供函数
     * @param <X>              异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberGtRange(long number, long leftOpenInterval, Supplier<X> supplier) throws X {
        if (!(number > leftOpenInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须大于等于指定范围
     *
     * @param number            数值
     * @param leftCloseInterval 左边界，为闭区间
     * @param supplier          异常提供函数
     * @param <X>               异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberGteRange(long number, long leftCloseInterval, Supplier<X> supplier) throws X {
        if (!(number >= leftCloseInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须小于指定范围
     *
     * @param number            数值
     * @param rightOpenInterval 右边界，为开区间
     * @param supplier          异常提供函数
     * @param <X>               异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberLtRange(long number, long rightOpenInterval, Supplier<X> supplier) throws X {
        if (!(number < rightOpenInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 数值必须小于等于指定范围
     *
     * @param number             数值
     * @param rightCloseInterval 右边界，为闭区间
     * @param supplier           异常提供函数
     * @param <X>                异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNumberLteRange(long number, long rightCloseInterval, Supplier<X> supplier) throws X {
        if (!(number < rightCloseInterval)) {
            throw supplier.get();
        }
    }

    /**
     * 字符串不能为空
     *
     * @param string   字符串
     * @param supplier 异常提供函数
     * @param <X>      异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNotBlank(String string, Supplier<X> supplier) throws X {
        if (!(Objects.nonNull(string) && string.length() > 0)) {
            throw supplier.get();
        }
    }

    /**
     * 集合不能为空
     *
     * @param collection 集合
     * @param supplier   异常提供函数
     * @param <X>        异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNotEmpty(Collection<?> collection, Supplier<X> supplier) throws X {
        if (!(Objects.nonNull(collection) && collection.size() > 0)) {
            throw supplier.get();
        }
    }

    /**
     * MAP 不能为空
     *
     * @param map      MAP
     * @param supplier 异常提供函数
     * @param <X>      异常类型
     * @throws X 异常
     */
    public static <X extends Throwable> void requireNotEmpty(Map<?, ?> map, Supplier<X> supplier) throws X {
        if (!(Objects.nonNull(map) && map.size() > 0)) {
            throw supplier.get();
        }
    }
}
